`define     MTIME_ADDR          2'b00
`define     MTIMECMP_ADDR       2'b01
`define     MSIP_ADDR           2'b10
module clint
( 
    input   wire                core_clk,
    input   wire                clint_clk,
    input   wire                rstn,
    input   wire                clint_mei_i,
    input   wire                WB_WEi,
    input   wire    [01:00]     WB_ADRi,
    input   wire    [63:00]     WB_DATi,
    output  reg     [63:00]     WB_DATo, 
    input   wire                WB_CYCi,
    input   wire                WB_STBi,
    output  reg                 WB_ACKo,
    output  wire                clint_mei_o,
    output  wire                clint_msi_o,
    output  wire                clint_mti_o

);
    reg     [63:00]     mtime;
    reg     [63:00]     mtimecmp;
    reg                 msip;
    always @( posedge core_clk ) begin
        if( !rstn )   begin
            mtimecmp        <=  64'b0;
            msip            <=  1'b0;
        end
        else begin
            if (WB_WEi && WB_STBi ) begin
                case (WB_ADRi)
                    `MTIMECMP_ADDR  :   mtimecmp        <=  WB_DATi;
                    `MSIP_ADDR      :   msip            <=  WB_DATi[00];
                    default         :   begin
                                            mtimecmp        <=  mtimecmp;
                                            msip            <=  msip    ;
                                        end
                endcase
            end
        end   
    end

    always @( posedge clint_clk ) begin
        if  ( !rstn )   	        mtime           <=  64'b0; 
        else    			        mtime           <=  mtime + 1;
    end


    always @( * ) begin
        case ( WB_ADRi )
            `MTIME_ADDR     :   WB_DATo    <=   mtime;
            `MSIP_ADDR      :   WB_DATo    <=   {63'b0,msip};
            `MTIMECMP_ADDR  :   WB_DATo    <=   mtimecmp;
            default         :   WB_DATo    <=   64'b0;
        endcase
    end
    assign  clint_mei_o     =   clint_mei_i;
    assign  clint_msi_o     =   (!clint_mei_i) & msip;
    assign  clint_mti_o     =   (!clint_mei_i) & (!msip) & (!(mtimecmp > mtime)) ;
    //
    always @( posedge core_clk ) begin
        if( WB_STBi )   WB_ACKo     <= 1'b1;
        else            WB_ACKo     <= 1'b0;
    end
endmodule